C.S.Burner 🪙 ━►🔥GIT Node
Node / reticulum_mirror / MeshChatX / files / meshchatx / src / frontend / components / DropDownMenu.vue
Displaying Raw • Download
meshchatx/src/frontend/components/DropDownMenu.vue 9ec2a88817819d433c5d68dbec0ca070ca989b91 (9ec2a888) Text, 3.95 KB
T8b949e<!-- SPDX-License-Identifier: 0BSD AND MIT -->
Tff7b72<templateTff7b72>
Tff7b72<div
Te6edf3v-click-outside=Ta5d6ff"Ta5d6ff{ handler: onClickOutsideMenu, capture: true }Ta5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffcursor-default relative inline-block text-leftTa5d6ff"
Tff7b72>
T8b949e<!-- menu button -->
Tff7b72<div Te6edf3ref=Ta5d6ff"Ta5d6ffdropdown-buttonTa5d6ff" Te6edf3class=Ta5d6ff"Ta5d6fftouch-manipulationTa5d6ff" @click.Te6edf3stop=Ta5d6ff"Ta5d6fftoggleMenuTa5d6ff"Tff7b72>
Tff7b72<slot Te6edf3name=Ta5d6ff"Ta5d6ffbuttonTa5d6ff" Tff7b72/>
Tff7b72</div>
Tff7b72<Teleport Te6edf3to=Ta5d6ff"Ta5d6ffbodyTa5d6ff"Tff7b72>
Tff7b72<Transition
Te6edf3enter-active-class=Ta5d6ff"Ta5d6fftransition ease-out duration-100Ta5d6ff"
Te6edf3enter-from-class=Ta5d6ff"Ta5d6fftransform opacity-0 scale-95Ta5d6ff"
Te6edf3enter-to-class=Ta5d6ff"Ta5d6fftransform opacity-100 scale-100Ta5d6ff"
Te6edf3leave-active-class=Ta5d6ff"Ta5d6fftransition ease-in duration-75Ta5d6ff"
Te6edf3leave-from-class=Ta5d6ff"Ta5d6fftransform opacity-100 scale-100Ta5d6ff"
Te6edf3leave-to-class=Ta5d6ff"Ta5d6fftransform opacity-0 scale-95Ta5d6ff"
Tff7b72>
Tff7b72<div
Te6edf3v-if=Ta5d6ff"Ta5d6ffisShowingMenu && dropdownPositionTa5d6ff"
Te6edf3ref=Ta5d6ff"Ta5d6ffdropdownPanelTa5d6ff"
Te6edf3class=Ta5d6ff"Ta5d6ffoverflow-x-hidden fixed z-[200] w-56 rounded-md bg-white dark:bg-zinc-800 shadow-lg border border-gray-200 dark:border-zinc-700 focus:outline-noneTa5d6ff"
Te6edf3:style=Ta5d6ff"Ta5d6ffdropdownPanelStyleTa5d6ff"
@click.Te6edf3stop=Ta5d6ff"Ta5d6ffhideMenuTa5d6ff"
Tff7b72>
Tff7b72<slot Te6edf3name=Ta5d6ff"Ta5d6ffitemsTa5d6ff" Tff7b72/>
Tff7b72</div>
Tff7b72</Transition>
Tff7b72</Teleport>
Tff7b72</div>
Tff7b72</template>
Tff7b72<scriptTff7b72>
import { clampFloatingToViewport } from "../js/clampFloatingToViewport.js";
export default {
name: "DropDownMenu",
data() {
return {
isShowingMenu: false,
dropdownPosition: null,
};
},
computed: {
dropdownPanelStyle() {
if (!this.dropdownPosition) {
return {};
}
const style = {
left: `${this.dropdownPosition.x}px`,
top: `${this.dropdownPosition.y}px`,
};
if (this.dropdownPosition.maxHeight != null) {
style.maxHeight = `${this.dropdownPosition.maxHeight}px`;
style.overflowY = "auto";
} else {
style.overflow = "hidden";
}
return style;
},
},
methods: {
toggleMenu() {
if (this.isShowingMenu) {
this.hideMenu();
} else {
this.showMenu();
}
},
showMenu() {
this.isShowingMenu = true;
this.adjustDropdownPosition();
},
hideMenu() {
this.isShowingMenu = false;
this.dropdownPosition = null;
},
onClickOutsideMenu() {
if (this.isShowingMenu) {
this.hideMenu();
}
},
adjustDropdownPosition() {
this.$nextTick(() => {
const button = this.$refs["dropdown-button"];
if (!button) return;
const buttonRect = button.getBoundingClientRect();
const menuWidth = 224;
let x = buttonRect.right - menuWidth;
x = Math.min(Math.max(8, x), window.innerWidth - menuWidth - 8);
const spaceBelow = window.innerHeight - buttonRect.bottom - 4;
const spaceAbove = buttonRect.top - 8;
let y = spaceBelow >= spaceAbove ? buttonRect.bottom + 4 : Math.max(8, buttonRect.top - 200 - 4);
this.dropdownPosition = { x, y, maxHeight: null };
this.$nextTick(() => {
const panel = this.$refs.dropdownPanel;
if (!panel) return;
const rect = panel.getBoundingClientRect();
const { left, top, maxHeight } = clampFloatingToViewport(rect.left, rect.top, rect.width, rect.height);
this.dropdownPosition = { x: left, y: top, maxHeight };
});
});
},
},
};
Tff7b72</script>
Served by rngit 1.5.2 - Generated in 0.03s